package com.kly.service.impl;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.kly.common.ErrorCode;
import com.kly.common.UserContext;
import com.kly.constant.UserConstant;
import com.kly.exception.BusinessException;
import com.kly.mapper.UserMapper;
import com.kly.model.domain.User;
import com.kly.model.dto.PageQuery;
import com.kly.model.vo.PageResult;
import com.kly.model.vo.UserVo;
import com.kly.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.kly.constant.UserConstant.*;

/**
 * @author admin
 * @description 针对表【user(用户表)】的数据库操作Service实现
 * @createDate 2025-02-15 18:58:12
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    private final UserMapper userMapper;

    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }


    /**
     * 用户注册
     *
     * @param account
     * @param password
     * @param checkPassword
     * @param planetCode
     * @return
     */
    @Override
    public long userRegister(String account, String password, String checkPassword, String planetCode) {
        // 判断非空
        if (StringUtils.isAnyBlank(account, password, checkPassword, planetCode)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不齐全");
        }
        // 账户长度不小于4 不大于16位
        if (account.length() < 4 || account.length() > 16) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户长度不小于4 不大于16");
        }

        // 账户密码不小于8位
        if (password.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码长度不小于8位");
        }
        // 账户不能有特殊字符
        if (!account.matches("^[a-zA-Z0-9_]+$")) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户不能有特殊字符");
        }
        // 二次密码相同
        if (!password.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次密码不一致");
        }
        // 星球编码验证 2-6位数字
        if (!planetCode.matches("^[0-9]{2,6}$")) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "星球编码 2-6位数字");
        }

        // 账户，星球编码不能重复
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .eq(User::getAccount, account)
                .eq(User::getPlanetCode, planetCode);
        long count = this.count(wrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户，星球编码不能重复");
        }


        // 密码加密 salt + password
        String encryptPassword = DigestUtils.md5DigestAsHex((password + SALT).getBytes());

        User user = new User();
        user.setAccount(account);

        user.setUsername(account);
        user.setAvatarUrl(UserConstant.DEFAULT_AVATAR);
        user.setPassword(encryptPassword);

        user.setPlanetCode(planetCode);

        // 加入数据库
        boolean saveResult = this.save(user);
        if (!saveResult) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "注册失败");
        }

        return user.getId();
    }

    @Override
    public UserVo userLogin(String account, String password) {
        // 校验账户密码
        // 判断非空
        if (StringUtils.isAnyBlank(account, password)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不齐全");
        }
        // 账户长度不小于4 不大于16位
        if (account.length() < 4 || account.length() > 16) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户长度不小于4 不大于16");
        }

        // 账户密码不小于8位
        if (password.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码长度不小于8位");
        }
        // 账户不能有特殊字符
        if (!account.matches("^[a-zA-Z0-9_]+$")) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户不能有特殊字符");
        }

        // 密码加密 salt + password
        String encryptPassword = DigestUtils.md5DigestAsHex((password + SALT).getBytes());

        // 账户验证 用户是否存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .eq(User::getAccount, account)
                .eq(User::getPassword, encryptPassword);
        User user = this.getOne(wrapper);

        // 未登录
        if (user == null) {
            log.info("login failed, account annot match password");
            throw new BusinessException(ErrorCode.NULL_ERROR, "用户名密码错误");
        }

        User safeUser = getSafetyUser(user);
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(safeUser, userVo);
        // 记录用户态
        // request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, safeUser);

        // 生成token
        // String token = UUID.randomUUID().toString()
        String token = UUID.randomUUID().toString(true);
        userVo.setToken(token);

        redisTemplate.opsForValue().set(LOGIN_USER_KEY + token, safeUser, LOGIN_STATE_EXPIRE_TIME, TimeUnit.MILLISECONDS);

        return userVo;
    }

    @Override
    public User getSafetyUser(User user) {
        if (user == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "系统错误");
        }
        // 用户信息脱敏
        User safeUser = new User();
        safeUser.setId(user.getId());
        safeUser.setAccount(user.getAccount());
        safeUser.setUsername(user.getUsername());
        safeUser.setAvatarUrl(user.getAvatarUrl());
        safeUser.setGender(user.getGender());
        safeUser.setPhone(user.getPhone());
        safeUser.setEmail(user.getEmail());
        safeUser.setStatus(user.getStatus());
        safeUser.setCreateTime(new Date());
        safeUser.setPlanetCode(user.getPlanetCode());
        safeUser.setRole(user.getRole());
        safeUser.setProfile(user.getProfile());
        safeUser.setTags(user.getTags());
        return safeUser;
    }


    @Override
    public List<User> searchUserByTags(List<String> tagNameList) {
        if (CollectionUtils.isEmpty(tagNameList)) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }

        // QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // for (String tagName : tagNameList) {
        //     queryWrapper =  queryWrapper.like("tags", tagName);
        // }
        // List<User> userList = this.list(queryWrapper);
        Gson gson = new Gson();
        List<User> userList = this.list();
        return userList.stream().filter(user -> {
            String tags = user.getTags();
            if (StringUtils.isBlank(tags)) {
                return false;
            }
            Set<String> tagList = gson.fromJson(tags, new TypeToken<Set<String>>() {
            }.getType());
            tagList = Optional.ofNullable(tagList).orElse(new HashSet<>());


            for (String tagName : tagNameList) {
                if (!tagList.contains(tagName)) {
                    return false;
                }
            }
            return true;
        }).map(this::getSafetyUser).collect(Collectors.toList());
    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        if (userObj == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        return (User) userObj;
    }

    @Override
    public Boolean isAdmin() {
        //     判断是否是管理员
        User currentUser = UserContext.getUser();
        return currentUser != null && currentUser.getRole().equals(UserConstant.ADMIN_ROLE);
    }

    @Override
    public Boolean isAdmin(User user) {
        return user != null && user.getRole().equals(UserConstant.ADMIN_ROLE);
    }

    @Override
    public Integer updateUser(User user, User loginUser) {
        if (user == null || loginUser == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 判断是否为管理员或修改user是否为自己
        Long id = user.getId();
        // if (!isAdmin(loginUser) && !id.equals(loginUser.getId())) {
        //     throw new BusinessException(ErrorCode.NO_AUTH);
        // }

        User userDb = userMapper.selectById(id);
        if (userDb == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }

        // 更新
        return userMapper.updateById(user);
    }

    @Override
    public PageResult<User> recommendUsers(PageQuery pageQuery) {
        int pageNo = pageQuery.getPageNo();
        int pageSize = pageQuery.getPageSize();
        // 分页查询
        Page<User> page = this.lambdaQuery()
                .orderByDesc(User::getUpdateTime)
                .page(new Page<>(pageNo, pageSize));
        List<User> userList = page.getRecords();
        // 用户脱敏
        List<User> users = userList.stream().map(this::getSafetyUser).collect(Collectors.toList());

        // 保存到redis
        PageResult<User> pageResult = PageResult.<User>builder()
                .records(users)
                .total(page.getTotal())
                .build();
        return pageResult;
    }
}




